﻿#region Creditos

/* Autor: Edilberto Sánchez Forero	*/
/* Email: esanchezfo@gmail.com		*/
/* Licencia: LGPL, Software Libre	*/
/* País: Colombia, Bogotá			*/

#endregion

#region Librerias

using System;
using System.Collections.Generic;
using System.Web.UI;
using System.Linq;
using System.Collections.Specialized;

using Microsoft.Reporting.WebForms;
using ESF.General;
using ESF.Web;
using System.Web.UI.WebControls;
using System.Text;
using System.IO;
using Ionic.Zip;
using ESF.MSReporting.WS;
using System.Net;
using System.Threading;
using System.Data;
using ESF.Web.Pages;
using System.Web;

#endregion


namespace ESF.MSReporting
{
	public abstract class ReportViewerBasePage : BasePage
    {
		#region Variables

		private string GUID;

		private List<Microsoft.Reporting.WebForms.ReportParameter> lstReportParameters;

		protected object ExtraData;

		#endregion


		#region Carga Inicial

		protected void Page_Load(object sender, EventArgs e)
		{
			Trace.Write ("Page.Load: Start");

			if (!IsPostBack)
			{
				Trace.Write("Page.Load.IsPostBack: Start");

				PageHelper.PreparePage (Page, PageHelper.PageDomain, false);

				Trace.Write("Page.Load.IsPostBack.LoadControls: Start");

				LoadControls ();

				JS.EnableLoadingMessage (Page, false);

				Trace.Write("Page.Load.IsPostBack.LoadControls: End");

				CustomLoad (Request.QueryString ["GUID"]);

				Trace.Write("Page.Load.IsPostBack: End");
			}

			Trace.Write("Page.Load: End");
		}
		
		#endregion
		
		
		#region Funciones
        
		protected virtual void LoadControls () {}


		protected virtual object GetLocalReportDataSet (string pReportServerURL, string pReportFolderPath, object pExtraData) { return null; }


		protected abstract ReportViewer GetReportViewerInstance ();
        
        
        private void CustomLoad (string pGUID)
        {
			NameValueCollection paramList;
			
			ReportViewer rpvReportViewer;
			
			Microsoft.Reporting.WebForms.ReportParameter tmpParam;

			bool doZip = false, doZipPassword = false, deleteOld = false;
			bool renderDirectly = true;
		
			string renderAs = null, renderToFilename = null, renderNotifyEmail = null, alternateDownloadURL = null;

			ReportExecutionService WSExecution;


			Trace.Write("Page.CustomLoad: Start");

			GUID = pGUID;

			rpvReportViewer = null;
			paramList = null;
			lstReportParameters = null;


			Trace.Write ("ReportViewer Base Page [ CUSTOM LOAD ] Start");

			try
			{
				rpvReportViewer = GetReportViewerInstance ();

				Trace.Write ("Configuring Report viewer...");

				#region JS

				JS.AddEndJS(Page, "var reportViewerControl; var reportViewerTimeoutID = 0; ShowLoadingMessage (); " +
					"Sys.Application.add_load (function () {" +
						" reportViewerControl = $find ('" + rpvReportViewer.ClientID + "'); " +
						" reportViewerTimeoutID = setTimeout (function () { if (!reportViewerControl.get_isLoading()) { " +
						" clearTimeout (reportViewerTimeoutID); HideLoadingMessage (); " + 
						" parent.FixSizeReportOnload (); " + 
						" } }, 800); });");
						
				#endregion


				rpvReportViewer.ShowReportBody = false;
				

				#region Validacion de Parametros de entrada
				
				if (!string.IsNullOrEmpty (pGUID))
				{
					paramList = MSReportingHelper.GetSessionPassedReportConfig (Page, pGUID);
				
					lstReportParameters = MSReportingHelper.GetSessionPassedReportParameters (Page, pGUID);

					ExtraData = PageHelper.GetRemoveSession (Page, "ExtraData" + GUID);
				}
				
				#endregion
				

				#region Set Render Parameters

				Trace.Write ("Setting render parameters...");

				if (lstReportParameters != null && lstReportParameters.Exists (rp => rp.Name == ReportParams.RENDERAS_PARAMNAME))
				{
					tmpParam = lstReportParameters.Find (rp => rp.Name == ReportParams.RENDERAS_PARAMNAME);
				
					renderAs = tmpParam.Values [0];

					Trace.Write ("RenderAs: " + renderAs);
					
					
					tmpParam = lstReportParameters.Find (rp => rp.Name == ReportParams.RENDERTOFILENAME_PARAMNAME);
					
					renderToFilename = (tmpParam == null ? null : tmpParam.Values [0]);

					Trace.Write ("RenderToFileName: " + renderToFilename);


					tmpParam = lstReportParameters.Find (rp => rp.Name == ReportParams.RENDER_NOTIFYEMAIL);
					
					renderNotifyEmail = (tmpParam == null ? null : tmpParam.Values [0]);

					Trace.Write ("RenderNotifyEmail: " + renderNotifyEmail);


					tmpParam = lstReportParameters.Find (rp => rp.Name == ReportParams.RENDER_DOZIP);
					
					doZip = (tmpParam == null ? false : TextHelper.GetBool (tmpParam.Values [0], false));

					Trace.Write ("DoZip: " + doZip);


					tmpParam = lstReportParameters.Find (rp => rp.Name == ReportParams.RENDER_DOZIPPASSWORD);
					
					doZipPassword = (tmpParam == null ? false : TextHelper.GetBool (tmpParam.Values [0], false));

					Trace.Write ("DoZipPassword: " + doZipPassword);


					tmpParam = lstReportParameters.Find (rp => rp.Name == ReportParams.RENDER_DELETEOLD);
					
					deleteOld = (tmpParam == null ? false : TextHelper.GetBool (tmpParam.Values [0], false));

					Trace.Write ("Deleteold: " + deleteOld);
				}

				#endregion

				
				#region More Render params

				if (lstReportParameters != null && lstReportParameters.Exists (rp => rp.Name == ReportParams.RENDER_DIRECTLY))
				{
					renderDirectly = TextHelper.GetBool (lstReportParameters.Find (rp => rp.Name == ReportParams.RENDER_DIRECTLY).Values [0], false);

					Trace.Write ("Configured to Rendering directly to browser: " + renderDirectly);
				}


				if (lstReportParameters != null && lstReportParameters.Exists (rp => rp.Name == ReportParams.ALLOW_EXPORT_REPORT))
				{
					rpvReportViewer.ShowExportControls = TextHelper.GetBool(lstReportParameters.Find(rp => rp.Name == ReportParams.ALLOW_EXPORT_REPORT).Values[0], false);
				}


				if (lstReportParameters != null && lstReportParameters.Exists(rp => rp.Name == ReportParams.ALLOW_PRINT_REPORT))
				{
					rpvReportViewer.ShowPrintButton = TextHelper.GetBool(lstReportParameters.Find(rp => rp.Name == ReportParams.ALLOW_PRINT_REPORT).Values[0], false);
				}


				if (paramList != null)
				{
					alternateDownloadURL = paramList [MSReportingHelper.ALTERNATEDOWNLOADURL_PARAM];

					Trace.Write ("Alternate download URL: " + alternateDownloadURL);
				}

				#endregion


				#region Prepare Report viewer

				if (lstReportParameters != null)
				{
					lstReportParameters.RemoveAll (
						rp => TextHelper.IsIn (rp.Name, 
						ReportParams.RENDERAS_PARAMNAME,
						ReportParams.RENDER_NOTIFYEMAIL,
						ReportParams.RENDER_PUBLISHFOLDER,
						ReportParams.RENDERTOFILENAME_PARAMNAME,
						ReportParams.RENDER_DOZIP,
						ReportParams.RENDER_DOZIPPASSWORD,
						ReportParams.RENDER_DELETEOLD,
						ReportParams.RENDER_DIRECTLY,
						ReportParams.ALLOW_PRINT_REPORT,
						ReportParams.ALLOW_EXPORT_REPORT));
				}

				if (paramList != null)
				{
					rpvReportViewer.ProcessingMode = (ProcessingMode)Enum.Parse(typeof(ProcessingMode), paramList[MSReportingHelper.REPORTVIEWER_PROCESSINGMODE]);
				}
				else
				{
					rpvReportViewer.ProcessingMode = ProcessingMode.Local;
				}

				if (rpvReportViewer.ProcessingMode == ProcessingMode.Remote)
				{
					Trace.Write("Processing mode Prepare: Remote Start");

					rpvReportViewer.ServerReport.Timeout = Timeout.Infinite;

					rpvReportViewer.ServerReport.ReportServerUrl = new Uri(paramList[MSReportingHelper.REPORTSERVER_URL_KEY]);

					rpvReportViewer.ServerReport.ReportServerCredentials =
						new CustomReportCredentials(
							paramList[MSReportingHelper.REPORTSERVER_USERNAME_KEY],
							paramList[MSReportingHelper.REPORTSERVER_USERPASSWORD_KEY],
							paramList[MSReportingHelper.REPORTSERVER_USERDOMAIN_KEY]);

					MSReportingHelper.PrepareReport(rpvReportViewer,
						paramList[MSReportingHelper.REPORTSERVER_FOLDERPATH],
						paramList[MSReportingHelper.REPORTPATH_PARAM],
						lstReportParameters,
						null);

					Trace.Write("Processing mode Prepare: Remote End");
				}
				else if (rpvReportViewer.ProcessingMode == ProcessingMode.Local)
				{
					Trace.Write("Processing mode Prepare: Local Start");

					MSReportingHelper.PrepareReport(
						rpvReportViewer, string.Empty,
						(paramList != null && paramList[MSReportingHelper.REPORTPATH_PARAM] != null ? paramList[MSReportingHelper.REPORTPATH_PARAM] : string.Empty),
						lstReportParameters,
						GetLocalReportDataSet(
							(paramList != null && paramList[MSReportingHelper.REPORTSERVER_FOLDERPATH] != null ? paramList[MSReportingHelper.REPORTSERVER_FOLDERPATH] : string.Empty),
							(paramList != null && paramList[MSReportingHelper.REPORTPATH_PARAM] != null ? paramList[MSReportingHelper.REPORTPATH_PARAM] : string.Empty),
							ExtraData));

					Trace.Write("Processing mode Prepare: Local End");
				}

				#endregion


				// Local
				if (rpvReportViewer.ProcessingMode == ProcessingMode.Local)
				{
					Trace.Write("Processing Render: Local Start");

					// Local y programado
					if (!renderDirectly)
					{
						RenderExtension (null, null, rpvReportViewer, lstReportParameters,
							renderAs, renderToFilename,
							renderNotifyEmail, doZip, doZipPassword, deleteOld, alternateDownloadURL);
					}
					// Local y directo
					else
					{
						// Formato general
						if (string.IsNullOrEmpty (renderAs))
						{
							MSReportingHelper.ShowReport (rpvReportViewer);
						}
						else
						{
							RenderExtensionDirect(null, paramList[MSReportingHelper.REPORTPATH_PARAM],
								rpvReportViewer, lstReportParameters,
								renderAs, renderToFilename, renderNotifyEmail,
								doZip, doZipPassword, deleteOld, alternateDownloadURL);
						}
					}

					Trace.Write("Processing Render: Local End");
				}
				// Remoto
				else
				{
					Trace.Write("Processing Render: Remote Start");

					// Remoto y Programado
					if (!renderDirectly)
					{
						WSExecution = new ReportExecutionService ();

						WSExecution.Timeout = Timeout.Infinite;

						WSExecution.Credentials = new NetworkCredential (
							paramList [MSReportingHelper.REPORTSERVER_USERNAME_KEY],
								paramList [MSReportingHelper.REPORTSERVER_USERPASSWORD_KEY],
								paramList [MSReportingHelper.REPORTSERVER_USERDOMAIN_KEY]);

						MSReportingHelper.PrepareReport (WSExecution, 
							paramList [MSReportingHelper.REPORTSERVER_FOLDERPATH],
							paramList [MSReportingHelper.REPORTPATH_PARAM], 
							lstReportParameters);

						RenderExtension (WSExecution, paramList [MSReportingHelper.REPORTPATH_PARAM], 
							null, lstReportParameters,
							renderAs, renderToFilename, renderNotifyEmail, 
							doZip, doZipPassword, deleteOld, alternateDownloadURL);
					}
					// Remoto y directo
					else
					{	
						// Formato general
						if (string.IsNullOrEmpty (renderAs))
						{
							MSReportingHelper.ShowReport (rpvReportViewer);
						}
						else
						{
							RenderExtensionDirect (null, paramList [MSReportingHelper.REPORTPATH_PARAM], 
								rpvReportViewer, lstReportParameters,
								renderAs, renderToFilename, renderNotifyEmail, 
								doZip, doZipPassword, deleteOld, alternateDownloadURL);
						}
					}

					Trace.Write("Processing Render: Remote End");
				}
			}
			catch (Exception pEx)
			{
				GenericException gEx;


				if (pEx is GenericException)
				{
					gEx = pEx as GenericException;
				}
				else
				{
					gEx = new GenericException ("Ha ocurrido un error al momento de mostrar el reporte", pEx);
				}

				if (lstReportParameters != null)
				{
					foreach (Microsoft.Reporting.WebForms.ReportParameter param in lstReportParameters)
					{
						gEx.Data.Add (param.Name, param.Values [0]);
					}
				}

				if (paramList != null)
				{
					foreach (string key in paramList.AllKeys)
					{
						gEx.Data.Add (key, paramList [key]);
					}
				}

				JS.LogError (Page, gEx);

				rpvReportViewer.Visible = false;
			}

			Trace.Write("Page.CustomLoad: End");
		}
		
		
		private void RenderExtension (ReportExecutionService pWS, string pReportPath,
			ReportViewer pReportViewer, List<Microsoft.Reporting.WebForms.ReportParameter> pParams, string pRenderAs, string pRenderToFilename, string pRenderNotifyEmail, 
			bool pDoZip, bool pDoZipPassword, bool pDeleteOld, string pAlternateDownloadURL)
		{
			string mimeType;
			string encoding;
			string fileNameExtension;
			string [] streamIDs;
			string fileNameURL;
			string reportTitle;

			Microsoft.Reporting.WebForms.Warning [] warnings;
			ESF.MSReporting.WS.Warning [] warningsWS;
			

			fileNameURL = PageHelper.GetVirtualPathFull (pRenderToFilename);

			Trace.Write ("Programming do and notify...");

			if (pReportViewer != null)
			{
				if (pReportViewer.ProcessingMode == ProcessingMode.Remote)
				{
					reportTitle = pReportViewer.ServerReport.DisplayName;
				}
				else
				{
					reportTitle = pReportViewer.LocalReport.DisplayName;

					pReportViewer.LocalReport.EnableExternalImages = true;
				}
			}
			else
			{
				reportTitle = Path.GetFileName (pReportPath);
			}

			ProcessHelper.DoAndNotifyEmail
			(
				"RenderReports",

				string.Format ("El reporte {0} ha sido generado", reportTitle),

				delegate (ref string pSubject, ref List<string> pTo, ref StringBuilder pBody, ref TextWriter pLogWriter, DateTime pStartDateTime)
				{
					byte [] RenderData;

					
					#region Render
						
					if (pReportViewer != null)
					{
						if (pReportViewer.ProcessingMode == ProcessingMode.Remote)
						{
							RenderData = pReportViewer.ServerReport.Render (pRenderAs, null, out mimeType, out encoding, out fileNameExtension, out streamIDs, out warnings);
						}
						else
						{
							RenderData = pReportViewer.LocalReport.Render (pRenderAs, null, out mimeType, out encoding, out fileNameExtension, out streamIDs, out warnings);
						}
					}
					else
					{
						RenderData = pWS.Render (pRenderAs, null, out fileNameExtension, out mimeType, out encoding, out warningsWS, out streamIDs);
					}
				
					if (RenderData != null && RenderData.Length > 0)
					{
						File.WriteAllBytes (pRenderToFilename, RenderData);

						MSReportingHelper.DeleteOldFilesZipNewFile (reportTitle, pRenderToFilename, fileNameURL, pStartDateTime, pParams, pDoZip, pDoZipPassword, pDeleteOld, pAlternateDownloadURL, ref pBody);
					}
					else
					{
						pBody.AppendLine ("No hay datos según los parametros indicados para mostrar el reporte");
					}

					#endregion
				},
				true,
				pRenderNotifyEmail
			);

			JS.AddWarning (Page, string.Format ("El reporte {0} ha sido programado, al estar listo le sera notificado mediante un correo electrónico a su cuenta en {1}", reportTitle, pRenderNotifyEmail));
		}


		private void RenderExtensionDirect(ReportExecutionService pWS, string pReportPath,
			ReportViewer pReportViewer, List<Microsoft.Reporting.WebForms.ReportParameter> pParams, string pRenderAs, string pRenderToFilename, string pRenderNotifyEmail,
			bool pDoZip, bool pDoZipPassword, bool pDeleteOld, string pAlternateDownloadURL)
		{
			string mimeType;
			string encoding;
			string fileNameExtension;
			string[] streamIDs;
			//string fileNameURL;
			string reportTitle;

			Microsoft.Reporting.WebForms.Warning[] warnings;
			ESF.MSReporting.WS.Warning[] warningsWS;


			pReportViewer.Visible = false;
			//fileNameURL = PageHelper.GetVirtualPathFull(pRenderToFilename);

			Trace.Write("Programming do and notify...");

			if (pReportViewer != null)
			{
				if (pReportViewer.ProcessingMode == ProcessingMode.Remote)
				{
					reportTitle = pReportViewer.ServerReport.DisplayName;
				}
				else
				{
					reportTitle = pReportViewer.LocalReport.DisplayName;

					pReportViewer.LocalReport.EnableExternalImages = true;
				}
			}
			else
			{
				reportTitle = Path.GetFileName(pReportPath);
			}

			byte[] RenderData;


			#region Render

			if (pReportViewer != null)
			{
				if (pReportViewer.ProcessingMode == ProcessingMode.Remote)
				{
					RenderData = pReportViewer.ServerReport.Render(pRenderAs, null, out mimeType, out encoding, out fileNameExtension, out streamIDs, out warnings);
				}
				else
				{
					RenderData = pReportViewer.LocalReport.Render(pRenderAs, null, out mimeType, out encoding, out fileNameExtension, out streamIDs, out warnings);
				}
			}
			else
			{
				RenderData = pWS.Render(pRenderAs, null, out fileNameExtension, out mimeType, out encoding, out warningsWS, out streamIDs);
			}

			if (!DataHelper.IsEmpty (RenderData))
			{
				if (string.IsNullOrEmpty (pRenderToFilename))
				{
					pRenderToFilename = Guid.NewGuid ().ToString ();
				}

				switch (pRenderAs)
				{
					case "Image":
						if (!pRenderToFilename.EndsWith(".png", StringComparison.InvariantCultureIgnoreCase))
						{
							pRenderToFilename += ".png";
						}

						Response.ContentType = "application/png";
					break;

					case "Word":
						if (!pRenderToFilename.EndsWith(".doc", StringComparison.InvariantCultureIgnoreCase))
						{
							pRenderToFilename += ".doc";
						}

						Response.ContentType = "application/msword";
					break;

					case "Excel":
						if (!pRenderToFilename.EndsWith(".xls", StringComparison.InvariantCultureIgnoreCase))
						{
							pRenderToFilename += ".xls";
						}

						Response.ContentType = "application/msexcel";
					break;

					case "PDF":
						if (!pRenderToFilename.EndsWith(".pdf", StringComparison.InvariantCultureIgnoreCase))
						{
							pRenderToFilename += ".pdf";
						}

						Response.ContentType = "application/pdf";
					break;

					default: 
						throw new NotSupportedException (string.Format ("Format is not supported: {0}", pRenderAs));
				}


				Response.Cache.SetCacheability(HttpCacheability.Private);  

				Response.AddHeader("content-disposition", string.Format(@"inline;filename=""{0}""", pRenderToFilename));

				Response.BinaryWrite (RenderData);
			}
			else
			{
				JS.AddWarning (Page, "No hay datos según los parametros indicados para mostrar el reporte");
			}

			#endregion
		}
		
		#endregion


		#region Manejo de Parametros

		protected string GetValueFromParams(List<Microsoft.Reporting.WebForms.ReportParameter> pParams, string pKey)
		{
			return GetValueFromParams(pParams, pKey, null);
		}


		protected string GetValueFromParams(List<Microsoft.Reporting.WebForms.ReportParameter> pParams, string pKey, string pDefaultValue)
		{
			Microsoft.Reporting.WebForms.ReportParameter temp;


			if (DataHelper.IsEmpty(pParams)) { return pDefaultValue; }

			temp = pParams.FirstOrDefault(p => p.Name == pKey);

			if (temp == null)
			{
				return null;
			}

			return temp.Values[0];
		}

		#endregion
    }
}